package x.ovo.wechat.bot;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import x.ovo.wechat.bot.command.DefaultCommandManager;
import x.ovo.wechat.bot.common.Constant;
import x.ovo.wechat.bot.common.Context;
import x.ovo.wechat.bot.common.http.WechatApi;
import x.ovo.wechat.bot.common.util.WechatUtil;
import x.ovo.wechat.bot.contact.DefaultContactManager;
import x.ovo.wechat.bot.core.ChatLoop;
import x.ovo.wechat.bot.core.Config;
import x.ovo.wechat.bot.core.MessageConsumer;
import x.ovo.wechat.bot.event.DefaultEventManager;
import x.ovo.wechat.bot.http.OkCookieJar;
import x.ovo.wechat.bot.login.HotReload;
import x.ovo.wechat.bot.plugin.DefaultPluginManager;

import java.time.Instant;
import java.util.concurrent.TimeUnit;

/**
 * 客户端
 *
 * @author ovo, created by 2024/04/18
 */
@Slf4j
@Getter
@Setter
public class WeChatClient {

    /** 操作微信接口的API */
    private WechatApi api;

    /** 上下文 */
    private Context context;

    /**
     * 创建一个客户端
     *
     * @param api api
     * @return {@link WeChatClient}
     */
    public static WeChatClient create(WechatApi api) {
        WeChatClient client = new WeChatClient();
        client.setApi(api);
        return client;
    }

    /**
     * 初始化
     */
    public WeChatClient init() {
        // 打印banner
        Config config = Config.get();
        if (config.isPrintBanner()) WechatUtil.printInfo();
        // 设置线程名称
        Thread.currentThread().setName("wechat-bot");
        // 注册关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
        // 创建必要文件
        this.mkDirs();
        // 创建上下文和各类管理器，管理器在创建时将自己注入上下文
        this.context = Context.create();
        this.context.setApi(this.api);
        this.api.setContext(this.context);
        this.context.setRunning(true);

        DefaultCommandManager.create(this.context);
        DefaultEventManager.create(this.context);
        DefaultPluginManager.create(this.context);
        DefaultContactManager.create(this.context);
        return this;
    }

    /**
     * 启动
     */
    public void start() {
        // 登录
        this.api.login(Config.get().isAutoLogin());
        // 初始化、获取登录用户信息及session
        this.api.init();
        // 刷新联系人信息
        this.context.getContactManager().flush();
        // 开启心跳同步守护线程、接收消息处理
        Thread thread = this.startHeartbeat();
//        this.monitor(thread);
        log.info("启动完成");
    }

    /**
     * 停止
     */
    public void stop() {
        this.context.setLogin(false);
        this.context.setRunning(false);
        this.api.statusNotify(null);
        this.context.getPluginManager().saveConfig();
        this.context.getLoginSession().setLastExitTime(System.currentTimeMillis() / 1000);
        HotReload.build(this.context.getLoginSession(), OkCookieJar.getCookieStore()).save();
        log.info("wechat-bot已停止，正在退出...");
    }

    /**
     * 创建一些必要的文件夹
     */
    private void mkDirs() {
        if (!Constant.CONFIG_DIR.exists()) FileUtil.mkdir(Constant.CONFIG_DIR);
        if (!Constant.PLUGIN_DIR.exists()) FileUtil.mkdir(Constant.PLUGIN_DIR);
        if (!Constant.LOG_DIR.exists()) FileUtil.mkdir(Constant.LOG_DIR);
//        if (!Constant.VIDEO_DIR.exists()) FileUtil.mkdir(Constant.VIDEO_DIR);
//        if (!Constant.IMAGE_DIR.exists()) FileUtil.mkdir(Constant.IMAGE_DIR);
    }

    /**
     * 启动心跳检测，并拉取新消息处理
     */
    private Thread startHeartbeat() {
        Thread thread = ThreadUtil.newThread(new ChatLoop(this.context), "wechat-listener");
        thread.start();
        // 启动消息消费线程
        ThreadUtil.newThread(new MessageConsumer(this.context), "consumer").start();
        return thread;
    }

    private void monitor (Thread thread){
        ThreadUtil.newThread(() -> {
            // 每隔5分钟检查一次
            ThreadUtil.safeSleep(TimeUnit.MINUTES.toMillis(5));
            long lastSyncCheckTime = this.context.getLastSyncCheckTime();
            long now = Instant.now().toEpochMilli();
            if (now - lastSyncCheckTime >= TimeUnit.MINUTES.toMillis(5)) {
                // 5分钟未同步消息，重启线程
                log.warn("5分钟未同步消息，重启服务");
                this.context.setRunning(false);
                ThreadUtil.safeSleep(TimeUnit.SECONDS.toMillis(1));
                this.context.setRunning(true);
                thread.start();
                log.info("重启服务成功");
            }
        }, "monitor").start();
    }

}
